/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prognosisdataalgo;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ApT
 */
public class Prognosis extends PrognosisFunction {

    /*
     * INITIALIZE VARIABLES
     */
    private Coordinate baseCoordinate;
    private List<Coordinate> positiveCoordinates;
    private List<Coordinate> negativeCoordinates;
    private DecimalFormat formater;

    /*
     * CONSTRUCTOR
     */
    public Prognosis() {
        this.formater = new DecimalFormat("#.##");
        positiveCoordinates = new ArrayList<Coordinate>();
        negativeCoordinates = new ArrayList<Coordinate>();
    }

    /*
     * SETTERS AND GETTERS
     */
    public List<Coordinate> getPositiveCoordinates() {
        return positiveCoordinates;
    }

    public void setPositiveCoordinates(List<Coordinate> positiveCoordinates) {
        this.positiveCoordinates.clear();
        this.positiveCoordinates.addAll(positiveCoordinates);
    }

    public List<Coordinate> getNegativeCoordinates() {
        return negativeCoordinates;
    }

    public void setNegativeCoordinates(List<Coordinate> negativeCoordinates) {
        this.negativeCoordinates.clear();
        this.negativeCoordinates.addAll(negativeCoordinates);
    }

    public Coordinate getBaseCoordinate() {
        return baseCoordinate;
    }

    public void setBaseCoordinate(Coordinate baseCoordinate) {
        this.baseCoordinate = baseCoordinate;
    }

    /*
     * PROGNOSIS FUNCTIONS
     */
    private double calculateListValue(List<Coordinate> coordinates) {
        double result = 0;
        for (Coordinate coordinate : coordinates) {
            result += coordinate.getValue() + coordinate.getDayFactorValue();
        }
        return result;
    }

    private void calculatePositiveFactorsValue(List<Coordinate> coordinates) {
        double listValue = calculateListValue(coordinates);
        for (Coordinate coordinate : coordinates) {
            coordinate.setFactorsValue(1 - ((coordinate.getValue() + coordinate.getDayFactorValue())
                    / listValue));
        }
    }

    private void calculateNegativeFactorsValue(List<Coordinate> coordinates) {
        double listValue = calculateListValue(coordinates);
        for (Coordinate coordinate : coordinates) {
            coordinate.setFactorsValue(((coordinate.getValue() + coordinate.getDayFactorValue())
                    / listValue));
        }
    }

    private double calculateImpact(Coordinate coordinate, List<Coordinate> positive) {
        double result = 0;
        for (Coordinate c : positive) {
            result += (coordinate.getFactorsValue() + c.getFactorsValue());
        }
        return result;
    }

    private double calculateImpact(List<Coordinate> negative) {
        double result = 0;
        for (Coordinate c : negative) {
            result += (c.getFactorsValue());
        }
        return result;
    }

    private double calculateAllDistanceBetwen(Coordinate coordinate, List<Coordinate> positive) {
        double result = 0;
        for (Coordinate c : positive) {
            result += (distance(coordinate.getCoordinate(), c.getCoordinate()));
        }
        return result;
    }

    private void calculateLowImpactFactors(List<Coordinate> positive, List<Coordinate> negative) {
        System.out.println("\nDistance betwen low impact factors:");
        for (Coordinate negCoordinate : negative) {
            double currentImpact = calculateImpact(negative);
            double distanceValue = calculateAllDistanceBetwen(negCoordinate, positive);
            for (Coordinate posCoordinate : positive) {
                double currentDistance = distance(negCoordinate.getCoordinate(), posCoordinate.getCoordinate());
                double templateDistanceValue = distanceValue - currentDistance;
                System.out.println(posCoordinate.getName() + "-" + negCoordinate.getName() + ": " + formater.format(currentDistance));
                double templateImpactValue = ((negCoordinate.getFactorsValue()));
                posCoordinate.addToLowImpactValue(templateDistanceValue * templateImpactValue);
            }
            System.out.println("");
        }
    }

    private void calculateDistanceImpact(Coordinate bsCoordinate, List<Coordinate> posCoordinates) {
        double allDistanceBetwen = calculateAllDistanceBetwen(bsCoordinate, posCoordinates);
        for (Coordinate coordinate : posCoordinates) {
            double betwen = distance(baseCoordinate.getCoordinate(), coordinate.getCoordinate());
            coordinate.setDistanceImpactValue(betwen * coordinate.getFactorsValue());

        }
    }

    private void calculateResultValue(List<Coordinate> posCoordinates) {
        double iV = 0;
        for (Coordinate coordinate : posCoordinates) {
            coordinate.setAllImpactValue(coordinate.getLowImpactValue() + coordinate.getDistanceImpactValue());
        }
        for (Coordinate coordinate : posCoordinates) {
            iV += coordinate.getAllImpactValue();
        }

        for (Coordinate coordinate : posCoordinates) {
            double templateIV = coordinate.getAllImpactValue();
            coordinate.setAllImpactValue(iV - templateIV);
        }

        for (Coordinate coordinate : posCoordinates) {
            iV += coordinate.getAllImpactValue();
        }

        for (Coordinate coordinate : posCoordinates) {
            double templateIV = coordinate.getAllImpactValue();
            coordinate.setAllImpactValue((templateIV / iV) * 100);
        }
    }

    private void calculateAfterFuzzyResult() {
        double allValue = 0;
        for (Coordinate coordinate : positiveCoordinates) {
            coordinate.setAfterFuzzyImpactValue(coordinate.getAllImpactValue() + coordinate.getFuzzyCorrectifyValue());
        }

        for (Coordinate coordinate : positiveCoordinates) {
            allValue += coordinate.getAfterFuzzyImpactValue();
        }

        for (Coordinate coordinate : positiveCoordinates) {
            coordinate.setAllCalculateResult((coordinate.getAfterFuzzyImpactValue() * 100) / allValue);
        }

    }

    public void calculateAll() {
        calculatePositiveFactorsValue(positiveCoordinates);
        calculateNegativeFactorsValue(negativeCoordinates);
        calculateLowImpactFactors(positiveCoordinates, negativeCoordinates);
        calculateDistanceImpact(baseCoordinate, positiveCoordinates);
        calculateResultValue(positiveCoordinates);
        calculateAfterFuzzyResult();
    }
    /*
     * DISPLAY FUNCTIONS
     */

    public void showPositiveDistance() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(baseCoordinate.getName() + " - " + coordinate.getName() + ": "
                    + formater.format(distance(baseCoordinate.getCoordinate(), coordinate.getCoordinate())) + " m");
        }
    }

    public void showPositiveFactorValues() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": "
                    + formater.format(coordinate.getFactorsValue()));
        }
    }

    public void showNegativeDistance() {
        for (Coordinate coordinate : negativeCoordinates) {
            System.out.println(baseCoordinate.getName() + " - " + coordinate.getName() + ": "
                    + formater.format(distance(baseCoordinate.getCoordinate(), coordinate.getCoordinate())) + " m");
        }
    }

    public void showNegativeFactorValues() {
        for (Coordinate coordinate : negativeCoordinates) {
            System.out.println(coordinate.getName() + ": "
                    + formater.format(coordinate.getFactorsValue()));
        }
    }

    public void showImpactValue() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": " + formater.format(coordinate.getLowImpactValue()));
        }
    }

    public void showDistanceImpactValue() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": " + formater.format(coordinate.getDistanceImpactValue()));
        }
    }

    public void showFinalResult() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": " + formater.format(coordinate.getAllImpactValue()));
        }
    }

    public void showAfterFuzzyResults() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": " + formater.format(coordinate.getAfterFuzzyImpactValue()));
        }
    }

    public void showFuzzyRules() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": " + coordinate.getDistanceFuzzy() + " | "
                    + coordinate.getNegativeFactorsFuzzy() + " | " + coordinate.getValuesFuzzy() + " || " + coordinate.getResultFuzzy());
        }
    }

    public void showAllResultValues() {
        for (Coordinate coordinate : positiveCoordinates) {
            System.out.println(coordinate.getName() + ": " + formater.format(coordinate.getAllCalculateResult()));
        }
    }
}
